package com.mtr.databoard.domain.screens;

import com.mtr.databoard.common.linqlist.LinqList;
import com.mtr.databoard.domain.components.ComponentStore;
import com.mtr.databoard.domain.components.ViewResource;
import com.mtr.databoard.domain.resources.ContextResource;
import com.mtr.databoard.domain.resources.ResourceEntity;
import com.mtr.databoard.domain.resources.ResourceStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Component
public class ScreenManager {
    private IScreentComponentRepository screentComponentRepository;
    private IScreenRepository screenRepository;
    private ComponentStore componentStore;
    private ResourceStore resourceStore;

    public ScreenManager(@Autowired IScreentComponentRepository screentComponentRepository, @Autowired IScreenRepository screenRepository, @Autowired ComponentStore componentStore, @Autowired ResourceStore resourceStore) {
        this.screentComponentRepository = screentComponentRepository;
        this.screenRepository = screenRepository;
        this.componentStore = componentStore;
        this.resourceStore = resourceStore;
    }


    /**
     * 创建大屏
     *
     * @param name
     * @return
     */
    public Screen createScreen(String name) {
        var screen = new Screen(name);
        screenRepository.insert(screen);
        return screen;
    }

    /**
     * 更新大屏封面
     *
     * @param screenId
     * @param cover
     */
    public void updateScreenBaseInfo(UUID screenId, String name, String description, ScreenResource cover) throws IOException {
        if (!screenRepository.existsById(screenId)) return;
        var screen = screenRepository.findById(screenId).get();

        var resources = new ArrayList<ContextResource>();

        var resourceEntity = new ResourceEntity(screen.getClass().getName(), screen.getId().toString());

        if (screen.getCover() != null && cover != null && !screen.getCover().toString().equals(cover.toString())) {
            resourceStore.unbindEntity(screen.getCover().getFileId(), resourceEntity);
        }
        if (cover != null) {
            resourceStore.bindEntity(cover.getFileId(), resourceEntity);
            resources.add(new ContextResource(cover.getFileId(), cover.getFileName()));
        }

        screen.setName(name);
        screen.setDescription(description);
        screen.setCover(cover);

        //重新释放资源
        resourceStore.releaseResources(resources, "screen", screen.getId().toString(), false);
        screenRepository.save(screen);
    }

    /**
     * 更新屏幕
     *
     * @param screenId
     * @param name
     * @param width
     * @param height
     * @param isAutoFit
     * @param components
     */
    public void updateScreen(UUID screenId, String name, int width, int height, boolean isAutoFit, List<ScreenComponent> components) throws IOException {
        if (!screenRepository.existsById(screenId)) return;
        var screen = screenRepository.findById(screenId).get();
        screen.setName(name);
        screen.setSize(width, height);
        screen.setAutoFit(isAutoFit);

        var oldComponents = screen.getComponents();
        //TODO 绑定或者释放资源
        var oldResources = getResourceIdFromComponents(oldComponents);


        var newResources = getResourceIdFromComponents(components);

        resourceStore.compareAndBindOrUnbindResource(oldResources, newResources, screen.getId().toString(), screen.getClass().getName());

        //直接以新的组件替换旧的组件
        screen.setComponents(components);

        if (screen.getCover() != null)
            newResources.add(new ContextResource(screen.getCover().getFileId(), screen.getCover().getFileName()));


        //重新释放资源
        resourceStore.releaseResources(newResources, "screen", screen.getId().toString(), true);

        screenRepository.save(screen);
    }

    /**
     * 复制大屏
     *
     * @param screenId
     * @return
     * @throws CloneNotSupportedException
     * @throws IOException
     */
    public Screen copyScreen(UUID screenId) throws CloneNotSupportedException, IOException {
        if (!screenRepository.existsById(screenId)) return null;
        var screen = screenRepository.findById(screenId).get();
        screen = screen.copy();
        var resources = getResourceIdFromComponents(screen.getComponents());
        if (screen.getCover() != null)
            resources.add(new ContextResource(screen.getCover().getFileId(), screen.getCover().getFileName()));

        resourceStore.compareAndBindOrUnbindResource(null, resources, screen.getId().toString(), screen.getClass().getName());
        //重新释放资源
        resourceStore.releaseResources(resources, "screen", screen.getId().toString(), true);

        screenRepository.insert(screen);
        return screen;
    }

    /**
     * 删除屏幕
     *
     * @param screenId
     */
    public void deleteScreen(UUID screenId) {
        if (!screenRepository.existsById(screenId)) return;
        var screen = screenRepository.findById(screenId).get();
        var resourceEntity = new ResourceEntity(screen.getClass().getName(), screen.getId().toString());
        var resources = getResourceIdFromComponents(screen.getComponents());
        for (var resource : resources) {
            resourceStore.unbindEntity(resource.getFileId(), resourceEntity);
        }
        screenRepository.deleteById(screenId);
    }


    /**
     * 获取组件的所有资源id
     *
     * @param components
     * @return
     */
    private List<ContextResource> getResourceIdFromComponents(List<ScreenComponent> components) {
        List<ContextResource> resourceIds = new ArrayList<>();
        if (components == null) return resourceIds;
        for (var screenComponent : components) {
            if (screenComponent.getView() != null) {
                var view = screenComponent.getView();
                if (view.getCover() != null)
                    resourceIds.add(new ContextResource(view.getCover().getFileId(), view.getCover().getFileName(), "view/" + view.getId()));
                if (view.getResources() != null) {
                    var resuources = view.getResources();
                    for (var resource : resuources) {
                        resourceIds.add(new ContextResource(resource.getFileId(), resource.getFileName(), "view/" + view.getId()));
                    }
                }

                var middleware = screenComponent.getMiddleware();
                if (middleware != null && middleware.getMiddleware() != null)
                    resourceIds.add(new ContextResource(middleware.getMiddleware().getFileId(), middleware.getMiddleware().getFileName(), "middleware/" + middleware.getId()));
            }
        }
        return resourceIds;
    }


    /**
     * 导入组件
     * 从视图组件导入，相当复制一份，资源也要重新保存一份的
     *
     * @param viewComponetIds 视图组件的id，非屏幕组件id
     * @return
     */
    public List<ScreenComponent> importComponents(List<UUID> viewComponetIds) {
        var lingList = new LinqList<>(viewComponetIds);
        return lingList.select(id -> {

            var componet = componentStore.getViewComponetById(id);
            if (componet == null) return null;

            var screenViewComponent = new ScreenViewComponent(
                    new ScreenResource(componet.getCover().getFileId(), componet.getCover().getFileName())
                    , componet.getName()
                    , componet.getCode()
                    , componet.getDescription()
                    , new ScreenViewSize(componet.getSize().getWidth(), componet.getSize().getHeight())
                    , new LinqList<ViewResource>(componet.getResources()).select(v -> {
                return new ScreenResource(v.getFileId(), v.getFileName());
            }).toList()
                    , componet.getHeadLinks()
                    , componet.getCodes()
                    , componet.getHtmlbody()
                    , new CustomerOptions(componet.getCustomerOptions().getOptions(),componet.getCustomerOptions().getValues())
            );
            var screenComponent = new ScreenComponent(screenViewComponent);
            return screenComponent;
        }).toList();
    }


    /**
     * 复制组件
     *
     * @param screenComponentId
     * @return
     */
    public ScreenComponent copyScreenComponent(UUID screenComponentId) throws CloneNotSupportedException {
        if (!screentComponentRepository.existsById(screenComponentId)) return null;
        var screenComponent = screentComponentRepository.findById(screenComponentId).get();
        screenComponent = screenComponent.copy();
        return screenComponent;
    }
}
